{extend name="layout/iframe_layout" /}

{block name="title"}在线更新{/block}
{block name="style"}
<style>
    .alert-warning {
        color: rgb(223, 42, 63);
    }
    .link-text {
        color: var(--larkx-editor-text-color);
    }
    .bold-link {
        font-weight: bold;
    }

    .diff-add {
        color: #22bb22;
        background: #ddffdd;
    }
    .diff-del {
        color: #bb2222;
        background: #ffdddd;
    }
    .diff-nor {
        color: #666;
    }
    .diff-tag {
        display: inline-block;
    }
    #app{
        padding: 20px;
        font-size: 16px;
    }
    .container{
        padding: 10px;
    }

    /* 添加更好的diff显示样式 */
    .diff-container {
        border: 1px solid #ddd;
        border-radius: 4px;
        overflow: hidden;
        margin: 20px 0;
        box-shadow: 0 1px 3px rgba(0,0,0,0.1);
    }

    .diff-header {
        background-color: #f7f7f7;
        padding: 10px 15px;
        border-bottom: 1px solid #ddd;
        font-weight: bold;
        color: #555;
        font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        display: flex;
        justify-content: space-between;
        align-items: center;
    }

    .diff-navigation {
        display: flex;
        align-items: center;
        gap: 10px;
    }

    .diff-nav-btn {
        background-color: #4CAF50;
        color: white;
        border: none;
        padding: 6px 12px;
        border-radius: 4px;
        cursor: pointer;
        font-size: 13px;
        transition: background-color 0.3s;
    }

    .diff-nav-btn:hover {
        background-color: #45a049;
    }

    .diff-nav-btn:disabled {
        background-color: #ccc;
        cursor: not-allowed;
    }

    .diff-nav-info {
        font-size: 13px;
        color: #666;
        min-width: 60px;
        text-align: center;
    }

    .diff-line.highlight {
        animation: highlight-flash 1.5s ease-in-out;
        box-shadow: 0 0 10px rgba(76, 175, 80, 0.5);
    }

    @keyframes highlight-flash {
        0% {
            background-color: #fff3cd;
            box-shadow: 0 0 15px rgba(255, 193, 7, 0.8);
        }
        50% {
            background-color: #ffe082;
            box-shadow: 0 0 20px rgba(255, 193, 7, 1);
        }
        100% {
            background-color: inherit;
            box-shadow: none;
        }
    }

    .diff-line-add.highlight {
        background-color: #c8e6c9 !important;
    }

    .diff-line-del.highlight {
        background-color: #ffcdd2 !important;
    }

    .diff-content {
        font-family: 'Courier New', Consolas, Monaco, monospace;
        font-size: 14px;
        line-height: 1.4;
        overflow-x: auto;
        max-height: 600px;
        overflow-y: auto;
        background-color: #fff;
    }

    .diff-line {
        white-space: pre;
        padding: 0 10px;
        display: flex;
    }

    .diff-line-add {
        background-color: #dfd;
    }

    .diff-line-del {
        background-color: #fdd;
    }

    .diff-line-nor {
        background-color: #fff;
    }

    .diff-line-number {
        display: inline-block;
        width: 50px;
        text-align: right;
        padding: 0 8px;
        color: #999;
        border-right: 1px solid #eee;
        margin-right: 8px;
        flex-shrink: 0;
    }

    .file-section {
        margin: 30px 0;
        padding: 20px;
        border-radius: 5px;
        background-color: #fafafa;
    }

    .file-section h2 {
        color: #333;
        border-bottom: 2px solid #4CAF50;
        padding-bottom: 10px;
    }

    .file-section h3 {
        color: #555;
        background-color: #eee;
        padding: 8px 12px;
        border-radius: 4px;
        margin: 15px 0 10px 0;
    }

    .added-file {
        color: #4CAF50;
        font-weight: bold;
    }

    .deleted-file {
        color: #F44336;
        font-weight: bold;
    }

    .changed-file {
        color: #2196F3;
        font-weight: bold;
    }

    #ajaxform {
        margin-top: 30px;
        padding: 20px;
        background-color: #f5f5f5;
        border-radius: 5px;
        text-align: center;
    }

    .update-btn {
        background-color: #4CAF50;
        color: white;
        padding: 12px 24px;
        border: none;
        border-radius: 4px;
        cursor: pointer;
        font-size: 16px;
        margin: 0 10px;
    }

    .update-btn:hover {
        background-color: #45a049;
    }

    .cancel-btn {
        background-color: #f44336;
        color: white;
        padding: 12px 24px;
        text-decoration: none;
        border-radius: 4px;
        font-size: 16px;
        margin: 0 10px;
    }

    .cancel-btn:hover {
        background-color: #d32f2f;
    }

    .error-message {
        color: #f00;
        padding: 20px;
        text-align: center;
    }

    /* 调整删除线样式 */
    .diff-line-del span {
        text-decoration: line-through;
    }

    /* 历史记录样式 */
    .history-section {
        margin-top: 30px;
        padding: 20px;
        background-color: #fafafa;
        border-radius: 5px;
    }

    .history-table {
        width: 100%;
        border-collapse: collapse;
        margin-top: 15px;
    }

    .history-table th,
    .history-table td {
        border: 1px solid #ddd;
        padding: 8px;
        text-align: left;
    }

    .history-table th {
        background-color: #f2f2f2;
        font-weight: bold;
    }

    .history-table tr:nth-child(even) {
        background-color: #f9f9f9;
    }

    .version-info {
        font-weight: bold;
        color: #2196F3;
    }
</style>
{/block}

{block name="content"}

<div id="app" >
    <div class="bg-white padding-20 page-min-height">
        <p class="font-size-16 margin-top-20">在线更新应用</p>

        <!-- 当前版本信息 -->
        <div class="container">
            <div class="layui-card">
                <div class="layui-card-header">当前版本信息</div>
                <div class="layui-card-body">
                    <p>当前线上版本：<span id="current-version">{{ currentVersion || '获取中...' }}</span></p>
                    <p>更新时间：<span id="update-time">{{ updateTime || '' }}</span></p>
                </div>
            </div>
        </div>

        <div class="notice">
            <p class="alert alert-warning">
                <i class="icon wb-info-circle" aria-hidden="true"></i>
                <span class="sr-only">提示：</span>
                1. 请上传zip格式的安装包，目录结构项目的目录结构，比如admin、api、web，文件放在相关目录下，比如<code>admin/controller/user.php</code><br>
                2. 压缩包内必须update/version.json文件，version.json文件内容如下：<br>
                <code>{
                    "version": "1.0.0",
                    "description": "更新描述"
                    }</code>
                <br>
                3. 仅支持覆盖文件、新增文件，不支持删除文件。所以应先用线上的代码作为源码修改。<br>
                4. 有sql数据库更新时，请在在update/下面新增sql文件，文件名必须为version.josn里面对应的"版本号.sql"，比如<code>1.0.0.sql</code>。<br>
                5. 请认真对比新增、修改的文件，以免造成数据丢失。<br>
            </p>
        </div>


        <!--上传安装包-->
        <div class="container">
            <form id="upload_form" enctype="multipart/form-data">
                <input type="file" name="file" id="file" @change="upload_file()">
            </form>
        </div>


        <div class="container" >
            <div v-html="html"></div>
        </div>
        <div v-if="html" id="ajaxform" onsubmit="return confirm('确认执行更新？')">
            <button class="update-btn" @click="start_update()">✅ 确认更新</button>
            <a  class="cancel-btn" @click="cancel_update()">❌ 取消更新</a>
        </div>

        <!-- 更新历史记录 -->
        <div class="history-section">
            <h2>更新历史记录</h2>
            <table class="history-table">
                <thead>
                <tr>
                    <th>版本号</th>
                    <th>更新时间</th>
                    <th>操作用户</th>
                    <th>描述</th>
                    <th>SQL更新</th>
                </tr>
                </thead>
                <tbody>
                <tr v-for="record in historyList" :key="record.id">
                    <td><span class="version-info">{{ record.version }}</span></td>
                    <td>{{ record.created_at }}</td>
                    <td>{{ record.operation_user_id }} </td>
                    <td><pre style="white-space: pre-wrap; word-wrap: break-word; margin: 0;">{{ record.description }}</pre></td>
                    <td>{{ record.has_sql==1 ? '是' : '否' }}</td>
                </tr>
                <tr v-if="historyList.length === 0">
                    <td colspan="5" style="text-align: center;">暂无更新记录</td>
                </tr>
                </tbody>
            </table>
            <div style="margin-top: 15px; text-align: center;">
                <button class="layui-btn layui-btn-primary" @click="loadMoreHistory" v-if="hasMoreHistory">加载更多</button>
                <span v-else>已加载全部记录</span>
            </div>
        </div>
    </div>

</div>
{/block}

{block name="script"}
<script src="/static/lib/jquery/jquery.min.js"></script>
    <!--别删除-->
    <!--hook_upload_m-->

<script>
    Vue.mixin(commonMethods);//引入公共方法

    //别删除
    //<hook_upload_m>
    var api_base = '/update';
    var auto_id = 'id';
    new Vue({
        el: '#app',
        data() {
            return {
                html: '',
                changes:[],
                tempUnzip:'',
                currentVersion: '',
                updateTime: '',
                historyList: [],
                historyPage: 1,
                hasMoreHistory: false,
            };
        },
        methods: {
            get_current_version: function() {
                let that = this;
                get(api_base+'/get_current_version')
                .then(res => {
                    if (res.code != 0) {
                        this.$message.error(res.msg || '获取当前版本失败');
                        return;
                    }
                    this.currentVersion = res.data.version;
                    this.updateTime = res.data.update_time || '';
                }).catch(error => {
                    console.error('获取当前版本失败:', error);
                });

            },
            get_update_history: function() {
                let that = this;
                get(api_base+'/get_update_history')
                .then(res => {
                    if (res.code == 0){
                        if (that.historyPage === 1) {
                        that.historyList = res.data.list;
                        } else {
                            that.historyList = that.historyList.concat(res.data.list);
                        }

                        // 判断是否还有更多数据
                        that.hasMoreHistory = that.historyList.length < res.data.total;
                    }

                }).catch(error => {
                    console.error('获取更新历史失败:', error);
                });
            },
            loadMoreHistory: function() {
                this.historyPage++;
                this.get_update_history();
            },
            upload_file: function () {
                let that = this;
                let formData = new FormData($('#upload_form')[0]);
                post(api_base+'/upload_app', formData).then(res => {
                    console.log('上传文件成功:', res);
                    if (res.code != 0) {
                        this.$message.error(res.msg || '上传文件失败');
                        //重置上传
                        $('#file').val('');
                        return;
                    }
                    that.html = res.data.html;
                    that.changes = res.data.changes;
                    that.tempUnzip = res.data.tempUnzip;

                    if (!that.html){
                        this.$message.error('这个安装包没有更新内容');
                        return;
                    }
                    // 初始化差异导航
                    that.$nextTick(function() {
                        setTimeout(function() {
                            // 执行所有script标签
                            $('.diff-container script').each(function() {
                                try {
                                    eval($(this).html());
                                } catch(e) {
                                    console.error('Error executing diff script:', e);
                                }
                            });
                            that.initDiffNavigation();
                            that.bindDiffNavigation();
                        }, 100);
                    });
                }).catch(error => {
                    //重置上传
                    $('#file').val('');
                    this.$message.error('上传文件失败');
                    console.error('上传文件失败:', error);
                });

            },
            start_update: function () {
                let c = confirm('确认执行更新？');
                if (c) {
                    let that = this;

                    post(api_base+'/start_update', {
                        changes: that.changes,
                        tempUnzip: that.tempUnzip
                    }).then(res => {
                        if (res.code != 0) {
                            this.$message.error(res.msg || '执行更新失败');
                            return;
                        }
                        this.$message.success(res.msg);
                        setTimeout(function() {
                            location.reload();
                        }, 1000)
                    }).catch(error => {
                        console.error('执行更新失败:', error);
                    });

                }
            },
            cancel_update(){
                let c = confirm('确认取消更新？');
                if (c) {
                    let that = this;
                    post(api_base+'/cancel_update', {
                        tempUnzip: that.tempUnzip
                    }).then(res => {
                        if (res.code != 0) {
                            this.$message.error(res.msg || '取消更新失败');
                            return;
                        }
                        this.$message.success(res.msg)
                        setTimeout(function() {
                            location.reload();
                        }, 1000)
                    }).catch( error=> {
                        console.error('取消更新失败:', error);
                    })

                }
            },
            initDiffNavigation: function() {
                // 初始化所有差异容器的导航状态
                $('.diff-container').each(function() {
                    var containerId = $(this).attr('id') || $(this).attr('data-container-id');
                    if (!containerId) return;

                    // 从script标签中获取修改点总数
                    var container = $(this);
                    var scriptTag = container.find('script').last();
                    if (scriptTag.length) {
                        try {
                            // 执行script标签中的代码来设置diffChangeCounts
                            eval(scriptTag.html());
                        } catch(e) {
                            console.error('Error executing diff script:', e);
                        }
                    }

                    if (window.diffChangeCounts && window.diffChangeCounts[containerId]) {
                        var total = window.diffChangeCounts[containerId];

                        // 初始化当前索引为0
                        container.attr('data-current-change', '0');

                        // 更新导航信息
                        var infoEl = $('#' + containerId + '-info');
                        if (infoEl.length) {
                            if (total > 0) {
                                infoEl.text('0 / ' + total);
                            } else {
                                infoEl.text('0 / 0');
                            }
                        }

                        // 初始化按钮状态
                        var prevBtn = container.find('.diff-nav-btn[data-nav-direction="prev"]');
                        var nextBtn = container.find('.diff-nav-btn[data-nav-direction="next"]');
                        prevBtn.prop('disabled', true); // 第一个，禁用上一个按钮
                        if (total > 0) {
                            nextBtn.prop('disabled', false);
                        } else {
                            nextBtn.prop('disabled', true);
                        }
                    }
                });
            },
            // 绑定差异导航
            bindDiffNavigation: function() {
                // 使用事件委托绑定导航按钮点击事件
                $(document).off('click', '.diff-nav-btn').on('click', '.diff-nav-btn', function(e) {
                    e.preventDefault();
                    e.stopPropagation();
                    var btn = $(this);
                    var containerId = btn.attr('data-container-id');
                    var direction = btn.attr('data-nav-direction');

                    console.log('Navigation button clicked:', containerId, direction);

                    if (containerId && direction) {
                        if (typeof window.diffNavigate === 'function') {
                            window.diffNavigate(containerId, direction);
                        } else {
                            console.error('diffNavigate function not found');
                        }
                    } else {
                        console.error('Missing containerId or direction:', containerId, direction);
                    }
                });
            }
        },

        created:function(){
            this.get_current_version();
            this.get_update_history();
        },
        mounted: function() {
            // 绑定导航事件
            this.bindDiffNavigation();
        },
    });

    // 全局差异导航函数
    window.diffNavigate = function(containerId, direction) {
        console.log('diffNavigate called:', containerId, direction);
        console.log('diffChangeCounts:', window.diffChangeCounts);

        if (!window.diffChangeCounts || !window.diffChangeCounts[containerId]) {
            console.warn('No change counts found for container:', containerId);
            return;
        }

        var container = $('#' + containerId);
        if (!container.length) {
            // 尝试通过data-container-id查找
            container = $('[data-container-id="' + containerId + '"]');
        }

        if (!container.length) {
            console.warn('Container not found:', containerId);
            return;
        }

        var total = window.diffChangeCounts[containerId];
        if (total === 0) {
            console.warn('No changes found in container:', containerId);
            return;
        }

        console.log('Total changes:', total);

        // 获取当前修改点索引
        var currentIndex = parseInt(container.attr('data-current-change') || '0');

        // 计算下一个/上一个索引
        var newIndex = currentIndex;
        if (direction === 'next') {
            newIndex = Math.min(currentIndex + 1, total);
        } else if (direction === 'prev') {
            newIndex = Math.max(currentIndex - 1, 0);
        }

        // 如果索引没有变化，说明已经到达边界
        if (newIndex === currentIndex) {
            return;
        }

        // 清除之前的高亮
        container.find('.diff-line.highlight').removeClass('highlight');

        // 更新当前索引
        container.attr('data-current-change', newIndex);

        // 更新导航信息
        var infoEl = $('#' + containerId + '-info');
        if (infoEl.length) {
            infoEl.text(newIndex + ' / ' + total);
        }

        // 更新按钮状态
        var prevBtn = container.find('.diff-nav-btn[data-nav-direction="prev"]');
        var nextBtn = container.find('.diff-nav-btn[data-nav-direction="next"]');
        prevBtn.prop('disabled', newIndex <= 0);
        nextBtn.prop('disabled', newIndex >= total || total === 0);

        // 如果索引为0，表示回到顶部，清除高亮
        if (newIndex === 0) {
            container.find('.diff-content').animate({
                scrollTop: 0
            }, 300);
            return;
        }

        // 找到目标修改点并高亮
        var targetId = containerId + '-change-' + newIndex;
        var targetEl = $('#' + targetId);

        if (targetEl.length) {
            // 高亮整个修改块（所有具有相同change-index的元素）
            var changeIndex = targetEl.attr('data-change-index');
            container.find('[data-change-index="' + changeIndex + '"]').addClass('highlight');

            // 滚动到目标位置
            var diffContent = container.find('.diff-content');
            var targetOffset = targetEl.offset().top;
            var containerOffset = diffContent.offset().top;
            var scrollTop = diffContent.scrollTop();
            var targetScrollTop = scrollTop + (targetOffset - containerOffset) - 100; // 留出100px的顶部空间

            diffContent.animate({
                scrollTop: targetScrollTop
            }, 300);
        }
    };

    // 键盘快捷键支持
    $(document).on('keydown', function(e) {
        // 检查是否在差异容器内
        var activeContainer = $('.diff-container:has(.diff-content:hover)').first();
        if (activeContainer.length) {
            var containerId = activeContainer.attr('id');
            if (e.key === 'ArrowUp' || e.key === 'u') {
                e.preventDefault();
                window.diffNavigate(containerId, 'prev');
            } else if (e.key === 'ArrowDown' || e.key === 'd') {
                e.preventDefault();
                window.diffNavigate(containerId, 'next');
            }
        }
    });

    // 页面加载完成后初始化导航
    $(document).ready(function() {
        setTimeout(function() {
            if (typeof vm !== 'undefined') {
                if (vm.initDiffNavigation) {
                    vm.initDiffNavigation();
                }
                if (vm.bindDiffNavigation) {
                    vm.bindDiffNavigation();
                }
            }
        }, 500);
    });
</script>
{/block}
